package xyz.imeans.w.service;

import com.dtflys.forest.exceptions.ForestNetworkException;
import com.xiaoleilu.hutool.json.JSONObject;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import xyz.imeans.w.annotion.Table;
import xyz.imeans.w.client.EsClient;
import xyz.imeans.w.config.CreateDataConfig;
import xyz.imeans.w.config.CreateEnum;
import xyz.imeans.w.config.InitCreateFactory;
import xyz.imeans.w.config.ObjCreateFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class EsService implements CreateService, InitializingBean {

    private final CreateDataConfig createDataConfig;
    private final EsClient esClient;
    public EsService(CreateDataConfig createDataConfig, EsClient esClient) {
        this.createDataConfig = createDataConfig;
        this.esClient = esClient;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        InitCreateFactory.initCreateService(CreateEnum.ES, this);
    }

    @Override
    public void exec(CreateDataConfig.Config config) {
        int count = config.getCount();
        if(count <= 0) {
            return;
        }
        try {
            Class<?> aClass = Class.forName(config.getModel());
            Table index = aClass.getAnnotation(Table.class);
            Map<String, String> map = createDataConfig.getSource().get("es");
            // 检查索引是否存在
            boolean needIndex = false;
            try {
                JSONObject mapping = esClient.getMapping(map.get("hostNames"), index.value());
                if (mapping.get(index.value()) == null) {
                    // 需要创建索引
                    needIndex = true;
                }
            } catch (ForestNetworkException e){
                // 需要创建索引
                if(e.getStatusCode() == 404) {
                    needIndex = true;
                }
            }

            // 获取表字段
            Map<String, String> columns = ObjCreateFactory.getFieldColumn(aClass);
            if(columns.size() == 0) {
                return;
            }

            // 创建索引
            if(needIndex) {
                JSONObject json = new JSONObject();
                JSONObject settings = new JSONObject();
                settings.put("number_of_shards", 5);
                settings.put("number_of_replicas", 1);
                JSONObject index1 = new JSONObject();
                index1.put("max_result_window", 1000000);
                settings.put("index", index1);
                json.put("settings", settings);
                JSONObject properties = new JSONObject();
                JSONObject keys = new JSONObject();
                JSONObject k = new JSONObject();
                k.put("type", "keyword");
                for (Map.Entry<String, String> entry : columns.entrySet()) {
                    if(!"my_system_data_id".equals(entry.getKey())) {
                        keys.put(entry.getValue(), k);
                    }
                }
                properties.put("properties", keys);
                json.put("mappings", properties);

                JSONObject indice = esClient.mapping(map.get("hostNames"), index.value(), json.toString());
                if(!indice.getBool("acknowledged")) {
                    return;
                }
            }

            // 生成数据
            List<Map<String, Object>> list = new ArrayList<>(count);
            for (int i = 0; i < count; i++) {
                Map<String, Object> d = ObjCreateFactory.createObj(aClass);
                if(d.size() > 0) {
                    list.add(d);
                }
            }
            if(list.size() == 0) {
                return;
            }

            String format = String.format("{\"create\":{\"_index\":\"%s\"}}", index.value());
            int num = list.size() / 2000 + (list.size() % 2000 > 0 ? 1 : 0);
            for (int c = 1; c <= num; c++) {
                List<Map<String, Object>> l = list.subList((c - 1) * 2000, Math.min(c * 2000, list.size()));
                StringBuilder sb = new StringBuilder();
                for (Map<String, Object> d : l) {
                    sb.append(format).append("\n");
                    for (Map.Entry<String, String> entry : columns.entrySet()) {
                        d.put(entry.getValue(), d.remove(entry.getKey()));
                    }
                    sb.append(new JSONObject(d)).append("\n");
                }
                esClient.bulk(map.get("hostNames"), index.value(), sb.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
